function getServerURL() {
    var serverURL = '';
    if (typeof app !== 'undefined' && app && typeof app == 'object' && (app?.getSetting || false) && typeof app.getSetting === 'function') {
        serverURL = app.getSetting('server_url') || '';
        if (serverURL.endsWith('/')) serverURL = serverURL.slice(0, -1);
    }
    return serverURL;
}
function update_thread_bookmark_buttons(data) {
    // Default style of all bookmark buttons
    $(`.bookmark-button`).off('click');
    $(`.bookmark-button`).empty().append(bsi('bookmark-plus'));
    $(`.bookmark-button`).attr('title', 'Bookmark this thread');
    $(`.bookmark-button`).on('click', function() {
        $(this).animate({ opacity: 0.5 }, 100);
        const chat_id = $(this).data('chat-id');
        const jwt = localStorage.getItem('jwt');
        fetch(`${getServerURL()}/my-bookmark-ids`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Accept': 'application/json',
                'Authorization': `Bearer ${jwt}`
            },
            body: JSON.stringify({ chat_id: chat_id }),
            credentials: 'include'
        })
            .then(response => response.json())
            .then(data => {
                if (data.ok) {
                    update_thread_bookmark_buttons(data);
                }
            });
    });

    // Update bookmark buttons for user's bookmarks
    const bookmark_ids = data?.bookmark_ids || [];
    for (var i = 0; i < bookmark_ids.length; i++) {
        const chat_id = bookmark_ids[i];
        const bookmark_button = $(`.bookmark-button[data-chat-id="${chat_id}"]`);
        if (bookmark_button.length) {
            bookmark_button.empty().append(bsi('bookmark-star-fill'));
            bookmark_button.attr('title', 'Remove bookmark');
        }
    }
    $(`.bookmark-button`).css('opacity', 1);
}
function render_threads(server_url = '', exit_callback = null) {
    $('.thread').each(function() {
        const thread = $(this);
        const skip_link = thread.hasClass('skip-link');
        const target_blank = (typeof server_url === 'string' && server_url.length > 0) ? ' target="_blank"' : '';

        // Text fields
        const content = thread.attr('data-content') || '';
        const url = thread.attr('data-url') || '';
        const channel = thread.attr('data-channel') || '';
        const replyCount = thread.attr('data-reply-count') || 0;

        // IDs 
        const chatId = thread.attr('data-chat-id') || '';
        const authorPublicKey = thread.attr('data-author-public-key') || '';
        const authorDisplayName = thread.attr('data-author-display-name') || '';
        const authorAlias = thread.attr('data-author-alias') || '';
        const authorPic = thread.attr('data-author-pic') || '';
        const datetimeCreated = thread.attr('data-datetime-created') || '';

        // Build HTML
        var replyStr = '';
        if (replyCount && !isNaN(replyCount * 1) && replyCount * 1) {
            replyStr = `<span><span class="text-muted small thread_reply_ticker">${replyCount}</span>&nbsp;${bsi('chat-fill')}</span>`;
        }
        var chat_link = `<a href="${server_url}/thread/${chatId}"${target_blank} class="link_to_thread" data-chat-id="${chatId}" data-author-public-key="${authorPublicKey}">${chatId}</a>`;
        if (skip_link) {
            chat_link = `<strong>${chatId}</strong>`;
        }
        var content_link = `<a href="${server_url}/thread/${chatId}"${target_blank} class="link_to_thread content_link" data-chat-id="${chatId}" data-author-public-key="${authorPublicKey}">${content}</a>`;
        if (skip_link) {
            content_link = content;
        }
        var exit_link = '';
        if (exit_callback && typeof exit_callback == 'function') {
            exit_link = `<a class="go-back-link" href="/" style="padding-right:10px;">←Exit</a>`;
        }
        var picImg = '';
        if (authorPic && typeof authorPic == 'string' && authorPic.length > 0 && authorPic.startsWith('http')) {
            picImg = `<img src="${authorPic}" class="rounded-circle" style="width:20px;height:20px;margin-right:5px;">`;
        }
        var aliasClass = '';
        if (authorAlias && typeof authorAlias == 'string' && authorAlias.length > 0) {
            aliasClass = 'has_alias';
        } else {
            aliasClass = 'no_alias';
        }
        thread.empty().append(`
             <small class="text-muted">
                 ${exit_link}${chat_link} by
                 <a href="${server_url}/profile/${authorPublicKey}"${target_blank} class="${aliasClass} user-profile-link" data-public-key="${authorPublicKey}">${picImg}${authorDisplayName.trim()}</a>
                 <span class="float-end text-muted">
                    ${replyStr}
                     <small class="text-muted relative-time" data-time="${datetimeCreated}">${datetimeCreated}</small>
                     <a class="bookmark-button text-muted small" data-chat-id="${chatId}" title="Bookmark this thread">
                     </a>
                 </span>
             </small>
             <br>
             <span class="thread-content-span">
                 ${channel ? `<span class="badge rounded-pill bg-primary"><a href="${server_url}/profile/${authorPublicKey}?channel=${channel}"${target_blank}>${channel}</a></span>` : ''} ${content_link}
             </span>
             <div class="reaction-container" data-chat-id="${chatId}">
                 <button class="btn btn-sm btn-outline-secondary text-muted" style="opacity:0.5;">
                     ⮝ ...
                  </button>
                 <button class="btn btn-sm btn-outline-secondary text-muted" style="opacity:0.5;">
                     ⮟ ...
                  </button>
             </div>
        `);
        thread.find('.bookmark-button').empty().append(bsi('bookmark-plus'));

        if (exit_callback && typeof exit_callback == 'function') {
            exit_link = thread.find('.go-back-link');
            exit_link.on('click', exit_callback);
        }

        if (url) {
            const link_toggle = $(`<a class="thread-link-toggle" data-chat-id="${chatId}" title="Toggle URL visibility">🔗</a>`);
            link_toggle.on('click', function() {
                const linkContainer = $(this).siblings('.thread-link-container');
                linkContainer.toggle(200);
            });
            thread.find('.thread-content-span').append(
                link_toggle,
                `
                <div class="thread-link-container" style="display:none;" data-chat-id="${chatId}">
                <a href="${url}" target="_blank" rel="noopener noreferrer">${url}</a>
                </div>`
            );
        }
        try {
            setTimeout(formatRelativeTime, 10);
        } catch (e) {
            console.error(e);
        }
    });

    // Update reactions (requires reactions.js)
    if (typeof loadBatchedReactions === 'function') {
        loadBatchedReactions();
    }

    // Add follow links (requires follow.js)
    init_follow_links(getServerURL());

    // Finally, get user bookmarks and update bookmark buttons
    fetch(`${getServerURL()}/my-bookmark-ids`, {
        method: 'GET',
        credentials: 'include'
    }).then(response => response.json()).then(data => {
        update_thread_bookmark_buttons(data);
    });
}